const vsSource = `
    attribute vec4 aVertexPosition;
    attribute vec4 aVertexColor;

    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;

    varying lowp vec4 vColor;

    void main(void) {
      gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
      vColor = aVertexColor;
    }
  `;

const fsSource = `
    varying lowp vec4 vColor;

    void main(void) {
      gl_FragColor = vColor;
    }
  `;

const vsSource_Tex = `
    attribute vec4 aVertexPosition;
    
    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;
    
    varying vec3 v_normal;
    
    void main(void) {
        gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
        v_normal = normalize(aVertexPosition.xyz);
    }
  `;

const fsSource_Tex = `
    precision mediump float;
    
    varying vec3 v_normal;
    
    uniform samplerCube u_texture;
    
    void main(void) {
        gl_FragColor = textureCube(u_texture, normalize(v_normal));
    }
  `;

//环境光着色器
const vsSource_AmbientLight = `
    attribute vec4 aVertexPosition;
    attribute vec4 aVertexColor;
    
    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;
    
    varying highp vec4 vColor;
    varying highp vec3 vLighting;
    
    void main(void) {
        gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
        vColor = aVertexColor;
        
        highp vec3 ambientLight = vec3(0.6, 0.6, 0.6);
        
        vLighting = ambientLight;
    }
  `;

const fsSource_AmbientLight = `
    varying highp vec4 vColor;
    varying highp vec3 vLighting;
    
    void main(void) {
        gl_FragColor = vec4(vColor.rgb * vLighting, vColor.a);
    }
  `;

const vsSource_DirectionalLight = `
    attribute vec3 aVertexNormal;
    attribute vec4 aVertexPosition;
    attribute vec4 aVertexColor;
    
    uniform mat4 uNormalMatrix;
    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;
    
    varying highp vec4 vColor;
    varying highp vec3 vLighting;
    
    void main(void) {
        gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
        vColor = aVertexColor;
        
        highp vec3 ambientLight = vec3(0.3, 0.3, 0.3);
        
        highp vec3 directionalLightColor = vec3(0.5, 0.5, 0.75);
        highp vec3 directionalVector = vec3(0.85, 0.8, 0.75);
        
        highp vec3 spotLightColor = vec3(0.8, 0.9, 0.8);
        highp vec3 spotLocation = vec3(-4, 10, -2);

        highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0);

        highp float directional = max(dot(transformedNormal.xyz, normalize(directionalVector)), 0.0);
        highp float spotdistance = max(dot(transformedNormal.xyz, normalize(spotLocation - aVertexPosition.xyz)), 0.0);
        vLighting = ambientLight + directionalLightColor * directional + spotLightColor * spotdistance;
    }
  `;

const fsSource_DirectionalLight = `
    varying highp vec4 vColor;
    varying highp vec3 vLighting;
    
    void main(void) {
        gl_FragColor = vec4(vColor.rgb * vLighting, vColor.a);
    }
  `;

const vsSource_Shadow1 = `
    attribute vec4 aVertexPosition;
    attribute vec4 aVertexColor;
    
    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;
    
    varying highp vec4 vColor;
    
    void main(void) {
        highp vec3 directionalVector = vec3(0.85, 0.8, 0.75);
        highp vec3 base = vec3(0.0, -2.0, 0.0);
        highp vec3 normal = vec3(0.0, 1.0, 0.0);
        
        vec3 position = (uModelViewMatrix * aVertexPosition).xyz;
        
        vec3 vloc = position - directionalVector * (dot(normal, (base - position)) / dot(normal, -directionalVector));
        gl_Position = uProjectionMatrix * vec4(vloc, 1);
        vColor = aVertexColor;
        vColor = vec4(0.1, 0.1, 0.1, 1.0);
    }
  `;

const fsSource_Shadow1 = `
    varying lowp vec4 vColor;

    void main(void) {
        gl_FragColor = vColor;
    }
  `

const vsSource_Shadow2 = `
    attribute vec4 aVertexPosition;
    attribute vec4 aVertexColor;
    
    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;
    
    varying highp vec4 vColor;
    
    void main(void) {
        highp vec3 directionalVector = vec3(-0.2, 0.5, 0.3);
        highp vec3 spotLocation = vec3(-4, 10, -2);
        highp vec3 base = vec3(0.0, -2.0, 0.0);
        highp vec3 normal = vec3(0.0, 1.0, 0.0);
        
        vec3 position = (uModelViewMatrix * aVertexPosition).xyz;
        
        vec3 vloc = position - (spotLocation - position) * (dot(normal, (base - position)) / dot(normal, (position - spotLocation)));
        gl_Position = uProjectionMatrix * vec4(vloc, 1);
        vColor = aVertexColor;
        vColor = vec4(0.1, 0.1, 0.1, 1.0);
    }
  `;

const fsSource_Shadow2 = `
    varying lowp vec4 vColor;

    void main(void) {
        gl_FragColor = vColor;
    }
  `
const vsSource_Eshadow= `
    attribute vec4 aVertexPosition;
    attribute vec4 aVertexColor;
    
    uniform mat4 uModelViewMatrix;
    uniform mat4 uProjectionMatrix;
    
    varying highp vec4 vColor;
    
    void main(void) {
        highp vec3 spoint1 = vec3(1.9, 2.4, -9.5999);
        highp vec3 spoint2 = vec3(1.9, -0.4, -9.5999);
        highp vec3 spoint3 = vec3(-0.9, -0.4, -9.5999);
        highp vec3 spoint4 = vec3(-0.9, 2.4, -9.5999);
        
        highp vec3 base = spoint1;
        
        highp vec3 normal = vec3(0.0, 0.0, 1.0);
        highp vec3 zerovec3 = vec3(0.0, 0.0, 0.0);
        
        vec3 position = (uModelViewMatrix * aVertexPosition).xyz;
        
        highp vec3 directionalVector = -normal;
        
        vec3 vloc = position - directionalVector * (dot(normal, (base - position)) / dot(normal, -directionalVector));
        float alpha = 1.0;
        

        if (dot(normal, (base - position)) > dot(normal, zerovec3)) {
            alpha = 0.0;
        }
        
        vec3 sec = vloc - spoint1;
        
        if (dot(sec, spoint2 - spoint1) / dot(spoint2 - spoint1, vec3(0, -1, 0)) > dot(spoint2 - spoint1, vec3(0, -1, 0)) || dot(sec, spoint2 - spoint1) < dot(normal, zerovec3)) {
            alpha = 0.0;
        }

        if (dot(sec, spoint4 - spoint1) / dot(spoint4 - spoint1, vec3(-1, 0, 0)) > dot(spoint4 - spoint1, vec3(-1, 0, 0)) || dot(sec, spoint4 - spoint1) < dot(normal, zerovec3)) {
            alpha = 0.0;
        }
        
        gl_Position = uProjectionMatrix * vec4(vloc, 1);
        vColor = aVertexColor;
        vColor = vec4(aVertexColor.xyz, alpha);
        // vColor = vec4(0.1, 0.1, 0.1, 1.0);
    }
  `;
function shaderInit(gl, vsSource, fsSource) {
    const vsShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
    const fsShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

    const shaderProgram = gl.createProgram();

    gl.attachShader(shaderProgram, vsShader);
    gl.attachShader(shaderProgram, fsShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
        return null;
    }

    return shaderProgram;
}

function loadShader(gl, type, source) {
    const shader = gl.createShader(type);

    gl.shaderSource(shader, source);
    gl.compileShader(shader);

    return shader;

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }
}

function createNormalShaderProgramInfo(gl) {
    const shaderProgram = shaderInit(gl, vsSource, fsSource);

    const shaderProgramInfo = {
        program: shaderProgram,

        attribLocations: {
            vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
            vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
        },

        uniformLocations: {
            projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
            modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
        },

        kind: 0,
    };

    return shaderProgramInfo;
}

function createTexShaderProgramInfo(gl) {
    const shaderProgram = shaderInit(gl, vsSource_Tex, fsSource_Tex);

    const shaderProgramInfo = {
        program: shaderProgram,

        attribLocations: {
            vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
        },

        uniformLocations: {
            projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
            modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
            texture: gl.getUniformLocation(shaderProgram, 'u_texture'),
        },

        kind: 2,
    };

    return shaderProgramInfo;
}

function createALightShaderProgramInfo(gl) {
    const shaderProgram = shaderInit(gl, vsSource_AmbientLight, fsSource_AmbientLight);

    const shaderProgramInfo = {
        program: shaderProgram,

        attribLocations: {
            vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
            vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
        },

        uniformLocations: {
            projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
            modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
        },

        kind: 0,
    };

    return shaderProgramInfo;
}

function createDLightShaderProgramInfo(gl) {
    const shaderProgram = shaderInit(gl, vsSource_DirectionalLight, fsSource_DirectionalLight);

    const shaderProgramInfo = {
        program: shaderProgram,

        attribLocations: {
            vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
            vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
            vertexNormal: gl.getAttribLocation(shaderProgram, 'aVertexNormal'),
        },

        uniformLocations: {
            projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
            modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
            normalMatrix: gl.getUniformLocation(shaderProgram, 'uNormalMatrix'),
        },

        kind: 1,
    };

    return shaderProgramInfo;
}

function createShadow1ProgramInfo(gl) {
    const shaderProgram = shaderInit(gl, vsSource_Shadow1, fsSource_Shadow1);

    const shaderProgramInfo = {
        program: shaderProgram,

        attribLocations: {
            vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
            vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
        },

        uniformLocations: {
            projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
            modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
        },

        kind: 0,
    };

    return shaderProgramInfo;
}

function createShadow2ProgramInfo(gl) {
    const shaderProgram = shaderInit(gl, vsSource_Shadow2, fsSource_Shadow2);

    const shaderProgramInfo = {
        program: shaderProgram,

        attribLocations: {
            vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
            vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
        },

        uniformLocations: {
            projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
            modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
        },

        kind: 0,
    };

    return shaderProgramInfo;
}

function createEshadowProgramInfo(gl) {
    const shaderProgram = shaderInit(gl, vsSource_Eshadow, fsSource_Shadow2);

    const shaderProgramInfo = {
        program: shaderProgram,

        attribLocations: {
            vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
            vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'),
        },

        uniformLocations: {
            projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
            modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
        },

        kind: 0,
    };

    return shaderProgramInfo;
}